/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * *
 *            Copyright (C) 2018 Institute of Computing Technology, CAS
 *               Author : Han Shukai (email : hanshukai@ict.ac.cn)
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * *
 *                  The shell acts as a task running in user mode. 
 *       The main function is to make system calls through the user's output.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * *
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this 
 * software and associated documentation files (the "Software"), to deal in the Software 
 * without restriction, including without limitation the rights to use, copy, modify, 
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 
 * persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * */

#include "screen.h"
#include "stdio.h"
#include "syscall.h"
#include "test.h"

#ifdef P3_TEST

struct task_info task1 = {"task1", (uint64_t)&ready_to_exit_task, USER_PROCESS,5};
struct task_info task2 = {"task2", (uint64_t)&wait_lock_task, USER_PROCESS,5};
struct task_info task3 = {"task3", (uint64_t)&wait_exit_task, USER_PROCESS,5};

struct task_info task4 = {"task4", (uint64_t)&semaphore_add_task1, USER_PROCESS,5};
struct task_info task5 = {"task5", (uint64_t)&semaphore_add_task2, USER_PROCESS,5};
struct task_info task6 = {"task6", (uint64_t)&semaphore_add_task3, USER_PROCESS,5};

struct task_info task7 = {"task7", (uint64_t)&producer_task, USER_PROCESS,5};
struct task_info task8 = {"task8", (uint64_t)&consumer_task1, USER_PROCESS,5};
struct task_info task9 = {"task9", (uint64_t)&consumer_task2, USER_PROCESS,5};

struct task_info task10 = {"task10", (uint64_t)&barrier_task1, USER_PROCESS,5};
struct task_info task11 = {"task11", (uint64_t)&barrier_task2, USER_PROCESS,5};
struct task_info task12 = {"task12", (uint64_t)&barrier_task3, USER_PROCESS,5};

struct task_info task13 = {"SunQuan", (uint64_t)&SunQuan, USER_PROCESS,5};
struct task_info task14 = {"LiuBei", (uint64_t)&LiuBei, USER_PROCESS,5};
struct task_info task15 = {"CaoCao", (uint64_t)&CaoCao, USER_PROCESS,5};
#endif

#ifdef P4_TEST
struct task_info task16 = {"mem_test1", (uint64_t)&rw_task1, USER_PROCESS};
struct task_info task17 = {"plan", (uint64_t)&drawing_task1, USER_PROCESS};
#endif

#ifdef P5_TEST
struct task_info task18 = {"mac_send", (uint64_t)&mac_send_task, USER_PROCESS};
struct task_info task19 = {"mac_recv", (uint64_t)&mac_recv_task, USER_PROCESS};
#endif

#ifdef P6_TEST

struct task_info task19 = {"fs_test", (uint64_t)&test_fs, USER_PROCESS};
struct task_info task20 = {"fs_test1", (uint64_t)&test_fs1, USER_PROCESS};
#endif
//struct task_info task16 = {"multcore", (uint64_t)&test_multicore, USER_PROCESS,5};
static struct task_info *test_tasks[2] = {
    &task19,
    &task20
    }
;


int atoi(const char *str)
{
    if (str == NULL)
        return 0;

    int result = 0;
    int sign = 1;
    if (('0' <= str[0] && str[0] <= '9') || (str[0] == '-') || str[0] == '+')
    {
        if (str[0] == '+' || str[0] == '-')
        {
            if (str[0] == '-')
            {
                sign = -1;
            }
            str++;
        }
    }
    else
    {
        return 0;
    }

    while ('0' <= *str && *str <= '9')
    {
        result = result * 10 + (*str++ - '0');
    }

    return result;
}
int htoi(char s[])
{
    int hexdigit, i, inhex, n;
    i = 0;
    if (s[i] == '0')
    {
        ++i;
        if (s[i] == 'x' || s[i] == 'X')
        {
            ++i;
        }
    }
    n = 0;
    inhex = 1;
    for ( ; inhex == 1; ++i)
    {
        if (s[i] >= '0' && s[i] <= '9')
        {
            hexdigit = s[i] - '0';
        }
        else if (s[i] >= 'a' && s[i] <= 'z')
        {
            hexdigit = s[i] - 'a' + 10;
        }
        else
        {
            inhex = 0;
        }
        if (inhex == 1)
        {
            n = 16 * n + hexdigit;
        }
    }
    return n;
}
void run_command(int argc, char argv[][30])
{
    if (argc == 1)
    {
        if (!strcmp(argv[0], "ps"))
        {
            sys_process_show();
        }
        else if (!strcmp(argv[0], "exit"))
            sys_exit();
        else if (!strcmp(argv[0], "time"))
            printf("current_time[%d]\n", get_timer());
        else if (!strcmp(argv[0], "clear"))
            sys_screen_clear(0,SCREEN_HEIGHT / 2);
        else if (!strcmp(argv[0], "mkfs"))
            sys_mkfs();
        else if (!strcmp(argv[0], "statfs"))
            sys_print_fs();
        else if (!strcmp(argv[0], "ls"))
            {
            argv[1][0] = '\0';
            sys_readdir((char *)argv[1]);
            }
        else
            printf("Unknown command!\n");
    }
    else if (argc == 2)
    {
        int pid = atoi((char *)argv[1]);
        if (!strcmp(argv[0], "exec"))
        {
            sys_spawn(test_tasks[pid]);
            printf("exec process[%d]\n", pid);
        }
        else if (!strcmp(argv[0], "kill"))
        {
            sys_kill(pid);
            printf("kill process pid = %d\n", pid);
        }
        else if(!strcmp(argv[0], "mkdir"))
        {
            sys_mkdir((char *)argv[1]);
        }
        else if(!strcmp(argv[0], "rmdir"))
        {
            sys_rmdir((char *)argv[1]);
        }
        else if(!strcmp(argv[0], "ls"))
        {
            sys_readdir((char *)argv[1]);
        }
        else if(!strcmp(argv[0], "cd"))
        {
            sys_enterdir((char *)argv[1]);
        }
        else if(!strcmp(argv[0], "touch"))
        {
            sys_mknod((char *)argv[1]);
        }
        else if(!strcmp(argv[0], "cat"))
        {
            sys_cat((char *)argv[1]);
        }
        else
            printf("Unknown command!\n");
    }
    else if (argc == 3)
    {
        int line1 = atoi((char *)argv[1]) + SCREEN_HEIGHT / 2;
        int line2 = atoi((char *)argv[2]) + SCREEN_HEIGHT / 2;
        if(!strcmp(argv[0],"clear"))
        {
            sys_screen_clear(line1,line2);
        }
        else if (!strcmp(argv[0], "scroll"))
        {
            sys_screen_scroll(line1, line2);
        }
        else if (!strcmp(argv[0], "ln"))
        {
            sys_hard_link((char *)argv[1], (char *)argv[2]);
        }
        else
            printf("Unknown command!\n");
    }
    else if (argc == 4)
    {
        int a0 = htoi(argv[2]);
        int a1 = htoi(argv[3]);
        int pid = atoi((char *)argv[1]);
        if (!strcmp(argv[0], "execargv"))
        {
            sys_spawn_argv(test_tasks[pid],a0,a1);
            printf("exec process[%d]\n", pid);
        }
        else if (!strcmp(argv[0], "ln") && !strcmp(argv[1],"-s"))
        {
            sys_soft_link((char *)argv[2], (char *)argv[3]);
        }
        else
            printf("Unknown command!\n");
    }
    else if (argc != 0)
        printf("Unknown command!\n");
}

void test_shell()
{
    char buffer[64];
    int i = 0;
    int argc;
    char argv[4][30];
    int j , k ;
    
    sys_move_cursor(0, SCREEN_HEIGHT / 2);
    printf("-------------------- COMMAND --------------------\n");
    printf("> root@UCAS_OS: ");

    while (1)
    {
        char c = 0;
        while(c == 0){
         c = sys_read_shell_buff();
         if (c == 0)
            sys_yield();
        }
        if ((c==0)||(i == 0 && (c == 0x7f || c == 8)))//del or backspace
            continue;
        printf("%c", c);
        if (c != '\r')
        {
            if (c == 8 || c == 0x7f)
                i--;
            else
                buffer[i++] = c;
            continue;
        }
        else
        {
            buffer[i++] = ' ';
            buffer[i] = '\0';
            j = 0;
            if (buffer[j] == ' ')
                for (; buffer[j] == ' ' && j < i; j++);
            argc = 0;
            k = 0;
            for (; j < i; j++)
            {
                if (buffer[j] == ' ')
                {
                    argv[argc++][k] = '\0';
                    k = 0;
                    for (; buffer[j] == ' ' && j < i; j++);
                }
                argv[argc][k++] = buffer[j];
            }
            run_command(argc, argv);
            i = 0;
            printf("> root@UCAS_OS: ");
        }
    }
}
